package org.luo.lan.client.factory;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.luo.lan.client.constants.AttrConstants;
import org.luo.lan.client.handlers.ClientTargetHandler;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

@Slf4j
public class SessionFactory {
    public static SessionFactory INSTANCE = new SessionFactory();
    private Map<String, NioSocketChannel> sessionChannelMap = new ConcurrentHashMap<>();

    private SessionFactory(){}

    /**
     * 创建目标会话
     * @param ctx
     * @param host
     * @param port
     * @param sessionKey
     * @param consumer
     */
    public void createSession(ChannelHandlerContext ctx, String host, int port, String sessionKey, Consumer<NioSocketChannel> consumer) {
        try {
            EventLoopGroup workerGroup = ctx.channel().eventLoop().parent();
            new Bootstrap().group(workerGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ClientTargetHandler());
                        }
                    })
                    .connect(host, port).addListener((ChannelFuture future) -> {
                        if (future.isSuccess()) {
                            NioSocketChannel channel = (NioSocketChannel) future.channel();
                            sessionChannelMap.put(sessionKey, channel);
                            log.debug("创建会话{}成功，当前sessionChannelMap.size={}", sessionKey, sessionChannelMap.size());
                            consumer.accept(channel);
                        }else{
                            consumer.accept(null);
                        }
                    }
            );
        } catch (Exception ex) {
            consumer.accept(null);
        }

    }

    /**
     * 创建代理会话
     * @param channel
     * @return
     */
    public String createSession(NioSocketChannel channel){
        String sessionKey = getSeesionKey();
        while (sessionChannelMap.putIfAbsent(sessionKey, channel) != null) {
            sessionKey = getSeesionKey();
        }
        log.debug("新增proxySessionKey={}，channel={}",sessionKey,channel);
        return sessionKey;
    }

    private String getSeesionKey() {
        String uuid=UUID.randomUUID().toString();
        return "client_"+uuid;
    }

    public void closeAllSeesionChannel() {
        sessionChannelMap.forEach((k, v) -> {
            if (v != null) {
                closeChannel(v);
            }
        });
    }

    public void closeSeesionChannel(String sessionKey) {
        NioSocketChannel channel = sessionChannelMap.get(sessionKey);
        if (channel != null) {
            closeChannel(channel);
        }
    }

    private void closeChannel(Channel channel) {
        channel.attr(AttrConstants.SEESION_KEY).set(null);
        channel.close();
        log.debug("目标会话通道" + channel + "关闭中...");
    }

    public NioSocketChannel removeSession(String sessionKey) {
        log.debug("客户端会话" + sessionKey + "移除成功！");
        return sessionChannelMap.remove(sessionKey);
    }

    public NioSocketChannel getSessionChannel(String sessionKey) {
        return sessionChannelMap.get(sessionKey);
    }

}
